/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/** ************************************************************************************************
 * @file     Xspi_Ip.h                                                                           *
 * @brief    This file contains interface header for CAN SSDK driver, ...                          *
 * @author   Department/Semidrive                                                                     *
 * @date     2025/02/25                                                              *
 *                                                                                                 *
 **************************************************************************************************/

#ifndef XSPI_IP_H
#define XSPI_IP_H

#include <debug.h>
#include "lld_platform.h"
#if defined (CFG_PLATFORM_MCAL)
#include "Fls_Cfg.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif


/* PRQA S 0750 EOF */

/***************************************************************************************************
 *                                 Global Macro definition                                         *
 **************************************************************************************************/
#define XSPI_BIT(nr) (((uint32_t)1u) << (nr))
#define XSPI_DIV_ROUND_UP(n,d) (((n) + (d) - 1U) / (d))
#define XSPI_ROUNDUP(a, b) (((a) + ((uint32_t)(b)-1U)) & ~((uint32_t)(b)-1U))
#define XSPI_ROUNDDOWN(a, b) ((a) & ~((uint32_t)(b)-1U))
#define XSPI_IS_ALIGNED(a, b) (0U == (((uint32_t)(a)) & (((uint32_t)(b))-1U)))
#define XSPI_MIN(a, b) (((a) < (b)) ? (a) : (b))
#define XSPI_MAX(a, b) (((a) > (b)) ? (a) : (b))
#define XSPI_ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))

#define XSPI_IP_NS_2_TICKS(hz, ns) (XSPI_DIV_ROUND_UP(XSPI_DIV_ROUND_UP(hz, 1000000u) * (ns), 1000u))
#define XSPI_IP_US_2_TICKS(hz, us) (XSPI_DIV_ROUND_UP(hz, 1000000u) * (us))
#define XSPI_IP_MS_2_TICKS(hz, ms) (XSPI_DIV_ROUND_UP(hz, 1000u) * (ms))

#define XSPI_RET_OK                     (0)
#define XSPI_RET_FAILED                 (-1)
#define XSPI_RET_PARAMETER_ERR          (-2)
#define XSPI_RET_TIMEOUT                (-3)
#define XSPI_RET_UNSUPPORT              (-4)
#define XSPI_RET_BUSY                   (-5)

#ifndef CONFIG_WITH_XSPI_DEBUG
#define CONFIG_WITH_XSPI_DEBUG 0
#endif



#if defined (CFG_PLATFORM_SSDK)
#include <cache.h>
#include <string.h>
#if (CONFIG_WITH_XSPI_DEBUG)
#include <debug.h>
#define XSPI_LOG_DEBUG(x...)            ssdk_printf(SSDK_DEBUG,x)
#define XSPI_LOG_ERROR(x...)            ssdk_printf(SSDK_ERR,x)
#else
#define XSPI_LOG_DEBUG(...)
#define XSPI_LOG_ERROR(...)
#endif /* #if (CONFIG_WITH_XSPI_DEBUG) */
#define XSPI_UDELAY(us)                 (void)udelay(us)
#define XSPI_MEMCMP(mem1, mem2, size)   memcmp(mem1, mem2, size)
#define XSPI_MEMCLR(dst, size)          memset(dst, 0x0u, size)

#define XSPI_CLEAN_CACHE(addr, size)           arch_clean_cache_range(addr, size)
#define XSPI_INVALIDATE_CACHE(addr, size)      arch_invalidate_cache_range(addr, size)
#define XSPI_IS_P0                             IS_P0

#elif defined (CFG_PLATFORM_MCAL)
#include <Mcal_MemLibc.h>
#if (CONFIG_WITH_XSPI_DEBUG)
#include <debug.h>
#define XSPI_LOG_DEBUG(x...)            DBG(x)
#define XSPI_LOG_ERROR(x...)            ERROR(x)
#else
#define XSPI_LOG_DEBUG(...)
#define XSPI_LOG_ERROR(...)
#endif /* #if (CONFIG_WITH_XSPI_DEBUG) */
#define XSPI_UDELAY(us)                 (void)Mcal_udelay(us)
#define XSPI_MEMCMP(mem1, mem2, size)   Mcal_MemCmp(mem1, mem2, size)
#define XSPI_MEMCLR(dst, size)          Mcal_MemClr(dst, size)

#ifndef FLS_NON_CACHEABLE_NEEDED
#define FLS_NON_CACHEABLE_NEEDED  (STD_OFF)
#endif
#if (FLS_NON_CACHEABLE_NEEDED == STD_OFF)
#include "Mcal_Cache.h"
#define XSPI_CLEAN_CACHE(addr, size)         (void) Mcal_CleanCache(addr, size)
#define XSPI_INVALIDATE_CACHE(addr, size)    (void) Mcal_InvalidateCache(addr, size)
#else
#define XSPI_CLEAN_CACHE(...)
#define XSPI_INVALIDATE_CACHE(...)
#endif /* #if (XSPI_NON_CACHEABLE_NEEDED == STD_OFF) */
#define XSPI_IS_P0                             (GET_MINOR_V(readl(VERSION_REG_ADDR)) == 0u)

#else
#error "Undefined macros CFG_PLATFORM_MCAL or CFG_PLATFORM_SSDK"
#endif /** #if defined (CFG_PLATFORM_MCAL) */

#define XSPI_IP_SINGLE_LANS     (0u)
#define XSPI_IP_DUAL_LANS       (1u)
#define XSPI_IP_QUAD_LANS       (2u)
#define XSPI_IP_OCTAL_LANS      (3u)
#define XSPI_IP_SDR             (0u)
#define XSPI_IP_DDR             (1u)

#define XSPI_IP_PROTO_DATA_LANS_LSB              (0)
#define XSPI_IP_PROTO_DATA_DIS_LSB               (2)
#define XSPI_IP_PROTO_DATA_RATE_LSB              (3)
#define XSPI_IP_PROTO_ADDRESS_LANS_LSB           (4)
#define XSPI_IP_PROTO_ADDRESS_DIS_LSB            (6)
#define XSPI_IP_PROTO_ADDRESS_RATE_LSB           (7)
#define XSPI_IP_PROTO_COMMAND_LANS_LSB           (8)
#define XSPI_IP_PROTO_COMMAND_RATE_LSB           (11)
#define XSPI_IP_PROTO_MODE_ENABLE_LSB            (16)
#define XSPI_IP_PROTO_INVERT_ENABLE_LSB          (17)
#define XSPI_IP_PROTO_OPCODE_LSB                 (24)
#define XSPI_IP_PROTO_MASK(x)                    ((x) & 0xFFFFFFu)
#define XSPI_IP_PROTO_ADDRESS_UNMASK(x)          ((x) & 0xFFFF0Fu)
#define XSPI_IP_PROTO_DATA_UNMASK(x)             ((x) & 0xFFFFF0u)
#define XSPI_IP_PROTO_ADDRESS_DATA_UNMASK(x)     ((x) & 0xFFFF00u)
#define XSPI_IP_OPCODE_MASK(x)                   (((x) >> XSPI_IP_PROTO_OPCODE_LSB) & 0xFFu)


#define XSPI_IP_PROTO(dataLans, dataRate, addressLans, addressRate, comandLans, comamdRate, invertOpcodeEn) \
    ((uint32_t)(dataLans) | ((uint32_t)(dataRate) << XSPI_IP_PROTO_DATA_RATE_LSB) | \
    ((uint32_t)(addressLans) << XSPI_IP_PROTO_ADDRESS_LANS_LSB) | ((uint32_t)(addressRate) << XSPI_IP_PROTO_ADDRESS_RATE_LSB) | \
    ((uint32_t)(comandLans) << XSPI_IP_PROTO_COMMAND_LANS_LSB) | ((uint32_t)(comamdRate) << XSPI_IP_PROTO_COMMAND_RATE_LSB) | \
    ((uint32_t)(invertOpcodeEn) << XSPI_IP_PROTO_INVERT_ENABLE_LSB))

#define XSPI_IP_X_0_X_PROTO(dataLans, dataRate, comandLans, comamdRate, invertOpcodeEn) \
    ((uint32_t)(dataLans) | ((uint32_t)(dataRate) << XSPI_IP_PROTO_DATA_RATE_LSB) | (1UL << XSPI_IP_PROTO_ADDRESS_DIS_LSB) | \
    ((uint32_t)(comandLans) << XSPI_IP_PROTO_COMMAND_LANS_LSB) | ((uint32_t)(comamdRate) << XSPI_IP_PROTO_COMMAND_RATE_LSB) | \
    ((uint32_t)(invertOpcodeEn) << XSPI_IP_PROTO_INVERT_ENABLE_LSB))

#define XSPI_IP_X_0_0_PROTO(comandLans, comamdRate, invertOpcodeEn) \
    ((1UL << XSPI_IP_PROTO_DATA_DIS_LSB) | (1UL << XSPI_IP_PROTO_ADDRESS_DIS_LSB) | \
    ((uint32_t)(comandLans) << XSPI_IP_PROTO_COMMAND_LANS_LSB) | ((uint32_t)(comamdRate) << XSPI_IP_PROTO_COMMAND_RATE_LSB) | \
    ((uint32_t)(invertOpcodeEn) << XSPI_IP_PROTO_INVERT_ENABLE_LSB))

#define XSPI_IP_PROTO_OPCODE(opcode, proto) ((((uint32_t)(opcode)) << XSPI_IP_PROTO_OPCODE_LSB) | XSPI_IP_PROTO_MASK(proto))

#define XSPI_IP_PROTO_ADDRESS(addressLans, addressRate , proto) \
    (((uint32_t)(addressLans) << XSPI_IP_PROTO_ADDRESS_LANS_LSB) | ((uint32_t)(addressRate) << XSPI_IP_PROTO_ADDRESS_RATE_LSB) | XSPI_IP_PROTO_ADDRESS_UNMASK(proto))

#define XSPI_IP_PROTO_DATA(addressLans, addressRate , proto) \
    ((uint32_t)(dataLans) | ((uint32_t)(dataRate) << XSPI_IP_PROTO_DATA_RATE_LSB) | XSPI_IP_PROTO_DATA_UNMASK(proto))

#define XSPI_IP_PROTO_ADDRESS_DIS(proto) ((1UL << XSPI_IP_PROTO_ADDRESS_DIS_LSB) | XSPI_IP_PROTO_ADDRESS_UNMASK(proto))

#define XSPI_IP_PROTO_DATA_DIS(proto) ((1UL << XSPI_IP_PROTO_DATA_DIS_LSB) | XSPI_IP_PROTO_DATA_UNMASK(proto))

#define XSPI_IP_PROTO_ADDRESS_DATA_DIS(proto) \
    ((1UL << XSPI_IP_PROTO_DATA_DIS_LSB) | (1UL << XSPI_IP_PROTO_ADDRESS_DIS_LSB) | XSPI_IP_PROTO_ADDRESS_DATA_UNMASK(proto))

#define XSPI_IP_DEV_SIZE_MASK       (0x1Fu)

typedef unsigned int   Xspi_BitFieldType;

typedef union {
    uint32_t u32;
    struct
    {
        Xspi_BitFieldType proto         : 24;
        Xspi_BitFieldType opcode        : 8;
    } sketch;
    struct
    {
        Xspi_BitFieldType dataLans       : 2;
        Xspi_BitFieldType dataDis        : 1;
        Xspi_BitFieldType dataRate       : 1;
        Xspi_BitFieldType addressLans    : 2;
        Xspi_BitFieldType addressDis     : 1;
        Xspi_BitFieldType addressRate    : 1;
        Xspi_BitFieldType comandLans     : 2;
        Xspi_BitFieldType reserved3      : 1;
        Xspi_BitFieldType comamdRate     : 1;
        Xspi_BitFieldType reserved4      : 4;
        Xspi_BitFieldType modeBitEn      : 1;
        Xspi_BitFieldType invertOpcodeEn : 1;
        Xspi_BitFieldType reserved5      : 6;
        Xspi_BitFieldType opcode         : 8;
    } detail;
} Xspi_IpProtoType;

typedef enum {
    XSPI_IP_DIRECR_READ = 0,
    XSPI_IP_DIRECR_WRITE,
    XSPI_IP_INDIRECR_READ,
    XSPI_IP_INDIRECR_WRITE
} Xspi_IpCmdSetupType;

typedef enum
{
    XSPI_IP_NORFLASH = 0,
    XSPI_IP_NANDFLASH,
    XSPI_IP_HYPERRAM,
} Xspi_DeviceType;

typedef enum
{
    XSPI_IP_FW_DIR_ONLY_WR = 0,
    XSPI_IP_FW_DIR_ONLY_RD,
    XSPI_IP_FW_DIR_BOTH_WR_RD
} Xspi_IpFwDirectionType;

typedef struct
{
    uint8_t masterId;
    uint8_t protId;
    Xspi_IpFwDirectionType direct;
} Xspi_IpFwConfigType;

typedef struct {
    Xspi_IpProtoType proto;
    uint8_t dummy;
    uint8_t addrBytes; /*  Valid when addressDis is false 0 bytes(no need addr) 3 bytes or 4 bytes */
    uint16_t modeCode; /* Valid when modeBitEn is true */
} Xspi_IpCommandType;

typedef struct {
    uint8_t id;
    uint32_t apbBase;
    uint32_t directBase;
    uint32_t refClkHz;
    uint32_t fifoSize;
    Xspi_DeviceType devType;
    uint32_t semagId;
    bool semagLockEnable;
    bool useRomConfig;
    int32_t (*setClkRate)(uint8_t id, uint32_t rate);
    uint32_t (*getClkRate)(uint8_t id);
} Xspi_IpHostStaticConfigType;

typedef struct {
    Xspi_IpHostStaticConfigType config;
    bool prefetchEnable;
    bool useDummyRead;
    bool rfdEnable;
} Xspi_IpHostConfigType;

typedef struct {
    Xspi_IpHostStaticConfigType config;
    bool prefetchEnable;
    bool useDummyRead;
    bool rfdEnable;

    uint32_t currentRefClkHz;
    uint32_t devSize[2];
    uint32_t totalSize;
    bool dqsEnable;
    bool hyperramEnable;
    Xspi_IpCommandType memoryReadCmd;
    Xspi_IpCommandType memoryWriteCmd;
} Xspi_IpHostType;

typedef int32_t Xspi_IpTrainingCheckCallbackType(void *arg);

int32_t Xspi_IpInit(Xspi_IpHostType *host, const Xspi_IpHostConfigType *config);

int32_t Xspi_IpTraining(Xspi_IpHostType *host, Xspi_IpTrainingCheckCallbackType callBack, void *callBackArg);

int32_t Xspi_IpMemoryRead(Xspi_IpHostType *host, uint32_t address, uint8_t* buf, uint32_t size);

int32_t Xspi_IpMemoryWrite(Xspi_IpHostType *host, uint32_t address, const uint8_t* buf, uint32_t size);

int32_t Xspi_IpCommandRead(Xspi_IpHostType *host, Xspi_IpCommandType *cmd, uint32_t address, uint8_t* buf, uint32_t size);

int32_t Xspi_IpCommandWrite(Xspi_IpHostType *host, Xspi_IpCommandType *cmd, uint32_t address, const uint8_t* buf, uint32_t size);

void* Xspi_Memcopy(void *dst, const void *src, uint32_t totalSize);

void Xspi_IpCommandSetup(Xspi_IpHostType *host, uint32_t memoryReadProto, uint8_t readDummy,
    uint32_t memoryWriteProto, uint8_t writeDummy, uint8_t addrWidth);

int32_t Xspi_IpRefclkSetup(Xspi_IpHostType *host, uint32_t refClkHz);

void Xspi_IpSizeSetup(Xspi_IpHostType *host, uint8_t cs, uint32_t size);

void Xspi_IpGetDevSize(Xspi_IpHostType *host, uint8_t csNum);

void Xspi_IpDqsEnable(Xspi_IpHostType *host, bool enable);

void Xspi_IpPotoSetup(Xspi_IpHostType *host);

int32_t Xspi_IpRfdSetup(Xspi_IpHostType *host);

void Xspi_IpByteSwapSetup(Xspi_IpHostType *host, bool enable);

int32_t Xspi_IpSetFirewall(Xspi_IpHostType *host, uint32_t addr,
                        uint32_t size, Xspi_IpFwConfigType const *config, uint32 num);

void Xspi_IpCacheFlush(Xspi_IpHostType *host, uint32_t addr, uint32_t length);

#ifdef __cplusplus
}
#endif
#endif /* XSPI_IP_H */

/* End of file */

